/**
 * Copyright 2008 Adam Ruggles.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package kiff.entity;

import java.util.Date;
import java.util.Set;
import java.util.TreeSet;

import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Version;

import kiff.enumerator.TopicType;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;

/**
 * Topic Entity.
 * @author Adam
 * @version $Id: Topic.java 72 2008-11-26 21:14:10Z a.ruggles $
 */
@Entity @Table(name = "topics")
public class Topic implements CoreEntity<Integer>, TrackAware, UpdateAware<Topic>, Comparable<Topic> {
    /**
	 * Serial Version UID.
	 */
	private static final long serialVersionUID = 4915481034069919424L;

	/**
     * A boolean flag on whether this topic has been approved.
     */
    private Boolean approved;

    /**
     * The date and time the topic was created.
     */
    private Date created;

	/**
     * User that created this topic.
     */
    private User creator;

	/**
     * The Username of the first post/creator.
     */
    private String creatorUsername;

	/**
     * The first post on this topic.
     */
    private Post firstPost;

	/**
     * The forum this topic belongs to.
     */
    private Forum forum;

	/**
     * A boolean flag that determines if this topic should be hidden or not.
     */
    private Boolean hidden;

	/**
     * The unique identifier of the Topic object.
     */
    private Integer id;

	/**
     * The last post on this topic.
     */
    private Post lastPost;

	/**
     * The last time this topic had a post.
     */
    private Date lastPosted;

	/**
     * The Username of the last post.
     */
    private String lastPostUsername;

	/**
     * The last time this topic was viewed.
     */
    private Date lastViewed;

	/**
     * The last time this topic was modified.
     */
    private Date modified;

	/**
     * The posts associated with the topic.
     */
    private Set<Post> posts = new TreeSet<Post>();

	/**
     * The number of replies/posts for this topic.
     */
    private Integer replies;

	/**
     * A boolean flag on whether this topic has been marked as reported.
     */
    private Boolean reported;

	/**
     * The subject of the topic.
     */
    private String subject;

	/**
     * A type flag for the topic (i.e. Normal, Sticky, Announcement, ...).
     */
    private TopicType type;

	/**
     * The version for optimistic concurrency control.
     */
    private Integer version;

	/**
     * Number of views this topic has received.
     */
    private Integer views;

	/**
	 * @see java.lang.Comparable#compareTo(java.lang.Object)
	 */
	public int compareTo(final Topic topic) {
		if (this.lastPosted == null || topic == null || topic.getLastPosted() == null) {
			return -1;
		}
		return this.lastPosted.compareTo(topic.getLastPosted());
	}

	/**
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(final Object obj) {
		if (this == obj) {
			return true;
		}
		if (!(obj instanceof Topic)) {
			return false;
		}
		Topic rhs = (Topic) obj;
		return new EqualsBuilder()
			.append(subject, rhs.getSubject())
			.append(created, rhs.getCreated())
			.isEquals();
	}

	/**
	 * Returns approved.
	 * @return Returns the approved.
	 */
	@Basic(optional = false)
	public Boolean getApproved() {
		return approved;
	}

    /**
     * Returns created.
     * @return Returns the created.
     */
    @Basic(optional = false) @Temporal(TemporalType.TIMESTAMP)
    public Date getCreated() {
        return created;
    }

    /**
     * Returns creator.
     * @return Returns the creator.
     */
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "creator_id")
    public User getCreator() {
        return creator;
    }
    
    /**
     * Returns creatorUsername.
     * @return Returns the creatorUsername.
     */
    @Basic(optional = false)
    public String getCreatorUsername() {
        return creatorUsername;
    }

    /**
     * Returns firstPost.
     * @return Returns the firstPost.
     */
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "first_post_id")
    public Post getFirstPost() {
        return firstPost;
    }

    /**
     * Returns forum.
     * @return Returns the forum.
     */
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "forum_id")
    public Forum getForum() {
        return forum;
    }

	/**
	 * Returns hidden.
	 * @return Returns the hidden.
	 */
	@Basic(optional = false)
	public Boolean getHidden() {
		return hidden;
	}

	/**
     * @see kiff.entity.CoreEntity#getId()
     */
	@Id @GeneratedValue(strategy = GenerationType.AUTO)
	public Integer getId() {
		return id;
	}

    /**
     * Returns lastPost.
     * @return Returns the lastPost.
     */
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "last_post_id")
    public Post getLastPost() {
        return lastPost;
    }

    /**
     * Returns lastPosted.
     * @return Returns the lastPosted.
     */
    @Basic(optional = false) @Temporal(TemporalType.TIMESTAMP)
    public Date getLastPosted() {
        return lastPosted;
    }

    /**
     * Returns lastPostUsername.
     * @return Returns the lastPostUsername.
     */
    @Basic(optional = false)
    public String getLastPostUsername() {
        return lastPostUsername;
    }

    /**
     * Returns lastViewed.
     * @return Returns the lastViewed.
     */
    @Temporal(TemporalType.TIMESTAMP)
    public Date getLastViewed() {
        return lastViewed;
    }

    /**
     * Returns modified.
     * @return Returns the modified.
     */
    @Basic(optional = false) @Temporal(TemporalType.TIMESTAMP)
    public Date getModified() {
        return modified;
    }

	/**
	 * Returns posts.
	 * @return Returns the posts.
	 */
	@OneToMany(mappedBy = "topic", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
	@org.hibernate.annotations.OptimisticLock(excluded = true)
	public Set<Post> getPosts() {
		return posts;
	}

	/**
     * Returns replies.
     * @return Returns the replies.
     */
    @Basic(optional = false) @org.hibernate.annotations.OptimisticLock(excluded = true)
    public Integer getReplies() {
        return replies;
    }

	/**
	 * Returns reported.
	 * @return Returns the reported.
	 */
	@Basic(optional = false)
	public Boolean getReported() {
		return reported;
	}

    /**
     * Returns subject.
     * @return Returns the subject.
     */
    @Column(length = 200, nullable = false)
    public String getSubject() {
        return subject;
    }

	/**
     * Returns type.
     * @return Returns the type.
     */
    @org.hibernate.annotations.Type(
            type = "kiff.enumerator.GenericEnumUserType",
            parameters = {
                    @org.hibernate.annotations.Parameter(
                            name  = "enumClass",               
                            value = "kiff.enumerator.TopicType"),
                    @org.hibernate.annotations.Parameter(
                            name  = "identifierMethod",
                            value = "getValue"),
                    @org.hibernate.annotations.Parameter(
                            name  = "valueOfMethod",
                            value = "fromValue")
            }
    )
    @Basic(optional = false)
    public TopicType getType() {
        return type;
    }

    /**
     * Returns version.
	 * @return Returns the version.
	 */
    @Version
	public Integer getVersion() {
		return version;
	}

    /**
     * Returns views.
     * @return Returns the views.
     */
    @Basic(optional = false) @org.hibernate.annotations.OptimisticLock(excluded = true)
    public Integer getViews() {
        return views;
    }

    /**
	 * @see java.lang.Object#hashCode()
	 */
	public int hashCode() {
		return new HashCodeBuilder(41, 3)
			.append(subject)
			.append(created)
			.toHashCode();
	}

    /**
     * Sets approved.
     * @param approved The approved to set.
     */
	public void setApproved(final Boolean approved) {
		this.approved = approved;
	}

    /**
	 * @see kiff.entity.TrackAware#setCreated(java.util.Date)
	 */
	public void setCreated(final Date created) {
		this.created = created;
	}

	/**
     * Sets creator.
     * @param creator The creator to set.
     */
    public void setCreator(final User creator) {
        this.creator = creator;
    }

    /**
     * Sets creatorUsername.
     * @param creatorUsername The creatorUsername to set.
     */
    public void setCreatorUsername(final String creatorUsername) {
        this.creatorUsername = creatorUsername;
    }

    /**
     * Sets firstPost.
     * @param firstPost The firstPost to set.
     */
    public void setFirstPost(final Post firstPost) {
        this.firstPost = firstPost;
    }

    /**
     * Sets forum.
     * @param forum The forum to set.
     */
    public void setForum(final Forum forum) {
        this.forum = forum;
    }

    /**
     * Sets hidden.
     * @param hidden The hidden to set.
     */
    public void setHidden(final Boolean hidden) {
        this.hidden = hidden;
    }

    /**
	 * @see kiff.entity.CoreEntity#setId(java.io.Serializable)
	 */
	public void setId(final Integer id) {
		this.id = id;
		
	}

	/**
     * Sets lastPost.
     * @param lastPost The lastPost to set.
     */
    public void setLastPost(final Post lastPost) {
        this.lastPost = lastPost;
    }

    /**
     * Sets lastPosted.
     * @param lastPosted The lastPosted to set.
     */
    public void setLastPosted(final Date lastPosted) {
        this.lastPosted = lastPosted;
    }

    /**
     * Sets lastPostUsername.
     * @param lastPostUsername The lastPostUsername to set.
     */
    public void setLastPostUsername(final String lastPostUsername) {
        this.lastPostUsername = lastPostUsername;
    }

    /**
     * Sets lastViewed.
     * @param lastViewed The lastViewed to set.
     */
    public void setLastViewed(final Date lastViewed) {
        this.lastViewed = lastViewed;
    }

    /**
	 * @see kiff.entity.TrackAware#setModified(java.util.Date)
	 */
	public void setModified(final Date modified) {
		this.modified = modified;
	}

	/**
	 * Sets posts.
	 * @param posts The posts to set.
	 */
	public void setPosts(final Set<Post> posts) {
		this.posts = posts;
	}

	/**
     * Sets replies.
     * @param replies The replies to set.
     */
    public void setReplies(final Integer replies) {
        this.replies = replies;
    }

    /**
     * Sets reported.
     * @param reported The reported to set.
     */
    public void setReported(final Boolean reported) {
        this.reported = reported;
    }

    /**
     * Sets subject.
     * @param subject The subject to set.
     */
    public void setSubject(final String subject) {
        this.subject = subject;
    }

    /**
     * Sets type.
     * @param type The type to set.
     */
    public void setType(final TopicType type) {
        this.type = type;
    }

    /**
     * Sets version.
	 * @param version The version to set.
	 */
	public void setVersion(final Integer version) {
		this.version = version;
	}

	/**
     * Sets views.
     * @param views The views to set.
     */
    public void setViews(final Integer views) {
        this.views = views;
    }

    /**
	 * @see java.lang.Object#toString()
     */
	public String toString() {
		return new ToStringBuilder(this)
			.append("id", id)
			.append("subject", subject)
			.append("created", created)
			.append("modified", modified)
			.append("views", views)
			.append("replies", replies)
			.append("lastPostUsername", lastPostUsername)
			.append("lastPosted", lastPosted)
			.toString();
	}

	/**
	 * @see kiff.entity.UpdateAware#update(java.lang.Object)
	 */
	public void update(final Topic entity) {
		if (entity.getApproved() != null) {
			this.approved = entity.getApproved();
		}
		if (entity.getFirstPost() != null) {
			this.firstPost = entity.getFirstPost();
		}
		if (entity.getForum() != null) {
			this.forum = entity.getForum();
		}
		if (entity.getHidden() != null) {
			this.hidden = entity.getHidden();
		}
		if (entity.getLastPost() != null) {
			this.lastPost = entity.getLastPost();
		}
		if (entity.getLastPosted() != null) {
			this.lastPosted = entity.getLastPosted();
		}
		if (entity.getLastPostUsername() != null) {
			this.lastPostUsername = entity.getLastPostUsername();
		}
		if (entity.getLastViewed() != null) {
			this.lastViewed = entity.getLastViewed();
		}
		if (entity.getPosts() != null) {
			this.posts = entity.getPosts();
		}
		if (entity.getReplies() != null) {
			this.replies = entity.getReplies();
		}
		if (entity.getReported() != null) {
			this.reported = entity.getReported();
		}
		if (entity.getSubject() != null) {
			this.subject = entity.getSubject();
		}
		if (entity.getType() != null) {
			this.type = entity.getType();
		}
		if (entity.getViews() != null) {
			this.views = entity.getViews();
		}
	}
}
